package main

import (
	"fmt"
	"net/http"
	"reflect"
)

type X int
type Y int

type user struct {
	name string
	age int
}
type manager struct {
	user
	title string
}

type A int
type B struct {
	A
}

func (A) av()  {

}
func (*A) ap()  {

}

func (B) bv()  {

}

func (*B) bp()  {

}
func main() {
	var a,b X = 100,200
	var c Y = 300
	ta,tb,tc := reflect.TypeOf(a),reflect.TypeOf(b),reflect.TypeOf(c)
	//类型判断
	fmt.Println(ta==tb,ta==tc)
	fmt.Println(ta.Kind() == tc.Kind())
	fmt.Println("---------------------")
	//直接够着一些基础复合类型
	m  := reflect.ArrayOf(10,reflect.TypeOf(byte(0)))
	n  := reflect.MapOf(reflect.TypeOf(""),reflect.TypeOf(byte(0)))
	fmt.Println(m,n)
	fmt.Println("---------------------")
	//传入对象应该区分基础类型和指针类型，因为他们不属于同一类型
	x :=100
	tx,tp:=reflect.TypeOf(x),reflect.TypeOf(&x)
	fmt.Println(tx,tp)
	fmt.Println(tx.Kind(),tp.Kind())
	//方法Elem()返回指针，数组，切片，字典（值）或者通道的基类型
	fmt.Println(tx ==tp.Elem())
	fmt.Println("---------------------")
	fmt.Println(reflect.TypeOf(map[string]int{}).Elem())
	fmt.Println(reflect.TypeOf([]int32{}).Elem())
	fmt.Println("---------------------")
	//只有获取结构体指针的基类型后，才能遍历他的字段
	var mgr manager
	t := reflect.TypeOf(&mgr)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		fmt.Println(f.Name,f.Type,f.Offset)
		if f.Anonymous {
			//输出匿名字段结构
			for x:=0;x<f.Type.NumField();x++{
				af := f.Type.Field(x)
				fmt.Println(" ",af.Name,af.Type)
			}
		}
	}

	//对于匿名字段，可以用多级索引(按定义顺序)直接访问
	//FieldByName 不支持多级名称，如有同名遮蔽，须通过匿名字段二次获取
	fmt.Println("---------------------")
	t1 := reflect.TypeOf(mgr)
	name ,_ := t1.FieldByName("name")
	fmt.Println(name.Name,name.Type)
	age := t1.FieldByIndex([]int{0,1})
	fmt.Println(age.Name,age.Type)

	fmt.Println("---------------------")
	var bb B
	tt := reflect.TypeOf(&bb)
	s := []reflect.Type{tt,tt.Elem()}
	for _ ,t := range s {
		fmt.Println(t,":")
		for i := 0; i < tt.NumMethod(); i++ {
			fmt.Println(" ",tt.Method(i))
		}
	}

	//反射可以探知当前包或者外包IDE费到处结构成员
	//相对于reflect而言，当前包和外包都是“外包“。
	fmt.Println("---------------------")
	var ss http.Server
	ttt := reflect.TypeOf(ss)

	for i := 0; i < ttt.NumField(); i++ {
		fmt.Println(ttt.Field(i).Name)
	}
}
